package com.demarc.pesquisas.infraestrutura.web.jsf;

import java.util.List;

import javax.el.ELContext;
import javax.el.ValueExpression;
import javax.faces.application.FacesMessage;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.component.UINamingContainer;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.validator.ValidatorException;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.omnifaces.util.Ajax;

import com.demarc.pesquisas.infraestrutura.excecao.InfraException;
import com.demarc.pesquisas.infraestrutura.excecao.NegocioException;
import com.demarc.pesquisas.infraestrutura.mensagem.Mensagem;
import com.demarc.pesquisas.infraestrutura.mensagem.MensagemJsfUtils;
import com.demarc.pesquisas.infraestrutura.mensagem.MensagemUtil;
import com.demarc.pesquisas.negocio.util.ConstantesMensagens;
import com.demarc.pesquisas.web.pagina.OperacaoEnum;

public class JsfUtil {

	private static final String LABEL = "label";

	public static String getLabel(FacesContext facesContext,
			UIComponent component) {

		Object label = component.getAttributes().get(LABEL);
		ValueExpression expression = null;

		if (label instanceof String && ((String) label).length() == 0) {
			expression = component.getValueExpression(LABEL);
			if (expression != null) {
				label = null; // NOPMD
			}
		}

		if (label != null) {
			return String.valueOf(label);
		}

		expression = expression == null ? component.getValueExpression(LABEL)
				: expression;
		if (expression != null) {
			return String.valueOf(expression.getValue(facesContext
					.getELContext()));
		}

		return component.getClientId(facesContext);
	}

	public static void addAtributoSessao(String atributoNome,
			Object atributoValor) {
		HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
				.getExternalContext().getSession(true);
		session.setAttribute(atributoNome, atributoValor);
	}

	public static Object getAtributoSessao(String atributoNome) {
		FacesContext context = FacesContext.getCurrentInstance();

		if (context != null) {
			HttpSession session = (HttpSession) context.getExternalContext()
					.getSession(true);
			return session.getAttribute(atributoNome);
		}

		return null;
	}

	public static void cleanSubmittedValues(UIComponent component) {
		if (component instanceof EditableValueHolder) {
			((EditableValueHolder) component).resetValue();
		}

		List<UIComponent> children = component.getChildren();

		if (component instanceof UINamingContainer) {
			children = ((UINamingContainer) component).getFacetsAndChildren()
					.next().getChildren();
		}

		for (UIComponent child : children) {
			cleanSubmittedValues(child);
		}
	}

	public static void adicionarMensagemAdvertencia(Mensagem mensagem) {
		adicionarMensagemAdvertencia(MensagemUtil.get(mensagem));
	}

	private static void adicionarMensagemAdvertencia(String detalhe) {
		adicionarMensagem(FacesMessage.SEVERITY_WARN, "Advertência:", detalhe);
	}

	public static void adicionarMensagemInfo(Mensagem mensagem) {
		adicionarMensagemInfo(MensagemUtil.get(mensagem));
	}

	private static void adicionarMensagemInfo(String detalhe) {
		adicionarMensagem(FacesMessage.SEVERITY_INFO, "Info:", detalhe);
	}

	public static void adicionarMensagemErro(NegocioException excecao) {
		adicionarMensagemErro(excecao.getMessage());
	}

	public static void adicionarMensagemErro(Mensagem mensagem) {
		adicionarMensagemErro(MensagemUtil.get(mensagem));
	}

	public static void adicionarMensagemErro(String detalhe) {
		String novoDetalhe = getDetalheDoArquivoMensagens(detalhe);
		adicionarMensagem(FacesMessage.SEVERITY_ERROR, "Erro:", novoDetalhe);
	}

	/**
	 * Procura o detalhe no arquivo de mensagens.
	 * 
	 * @param detalhe
	 *            o texto que deseja procurar no arquivo de mensagens
	 * @return Caso o sistema encontre mensagem no arquivo de mensagens, retorna
	 *         a mensagem do arquivo. Caso contrário, retorna o próprio detalhe.
	 */
	private static String getDetalheDoArquivoMensagens(String detalhe) {
		// se o detalhe não tiver underline é porque não é do arquivo de
		// mensagens
		if (StringUtils.containsNone(detalhe, "_")) {
			return detalhe;
		}

		String novoDetalhe = null;
		try {
			novoDetalhe = MensagemUtil.get(detalhe);
		} catch (Exception ex) {
			novoDetalhe = detalhe;
		}

		return novoDetalhe;
	}

	private static void adicionarMensagem(Severity severidade, String titulo,
			String detalhe) {
		FacesContext.getCurrentInstance().addMessage(null,
				new FacesMessage(severidade, titulo, detalhe));
	}

	public static void executarJavascript(String javascriptMetodo) {
		Ajax.oncomplete(javascriptMetodo);
	}

	public static void subirPosicaoTela() {
		JsfUtil.executarJavascript("$(window).scrollTop(0)");
	}

	// FIXME atg - Ver a utilizada desse método redirecionarPagina
	public static void redirecionarPagina(String url) {
		try {
			ExternalContext externalContext = FacesContext.getCurrentInstance()
					.getExternalContext();
			if (!externalContext.isResponseCommitted()) {
				externalContext.redirect(url);
			}
		} catch (Exception ex) {
			throw new InfraException(ex);
		}
	}

	/**
	 * Adicionar "?faces-redirect=true" na página e que será usada por botões
	 * com ajax = "true". ajax button is "true".
	 * 
	 * @param pagina
	 * 
	 * @return pagina + ?faces-redirect=true
	 */
	public static String avancarParaPagina(String pagina) {
		return StringUtils.isBlank(pagina) ? pagina : pagina
				+ "?faces-redirect=true";
	}

	public static String getTituloPagina(OperacaoEnum operacao,
			String nomeFuncionalidade) {
		return MensagemUtil.get(ConstantesMensagens.TITULO_PAGINA,
				operacao.getChavePropertiesOperacao(), nomeFuncionalidade);
	}

	public static Object getBean(String beanName) {
		ELContext elContext = FacesContext.getCurrentInstance().getELContext();
		return elContext.getELResolver().getValue(elContext, null, beanName);
	}

	public static void throwValidatorException(String keyError,
			FacesContext context, String... params) {

		FacesMessage facesMessage = MensagemJsfUtils.criarFacesMessage(
				FacesMessage.SEVERITY_ERROR, keyError, params);
		throw new ValidatorException(facesMessage);
	}
}
